package gui.geometry;

import gui.Paintbrush;

import java.awt.BasicStroke;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Point;
import model.NetworkNode;

public class NetworkNodeDescriptor extends GeometryDescriptor {

	private Point pressPoint, dragPoint;
	private int nameWidth;
	public NetworkNodeDescriptor(NetworkNode object, Point point, FontMetrics fm) {
		super(object, point);
		nameWidth = fm.stringWidth(object.getName());
	}

	public static GeometryDescriptor contains(Point point, NetworkNode node, FontMetrics fm) {
		int w = fm.stringWidth(node.getName());
		int width = ((int)(w / 2 * 1.2) / 10 + 1) * 10;
		int height = ((int)(w / 2 * .5) / 10 + 1) * 10;
		
		//Inside
		if(!bounded(point, node, width, height) || Math.pow((double)Math.abs(point.x - node.getX()) / (width + 5), 2) 
				+ Math.pow((double)Math.abs(point.y - node.getY()) / (height + 5), 2) > 1) {
			return null;
		}
		
		//Check if in text
		GeometryDescriptor descriptor = TextDescriptor.contains(point, node, fm);
		if(descriptor != null) {
			return descriptor;
		}
		
		//Distance
		double [] quadrant = getQuadrant(point, node);
		double tMin = quadrant[0];
		double tMax = quadrant[1];
		
		while(Math.abs(tMax - tMin) > .0005) {
			double xMax = width * Math.cos(2 * Math.PI * tMax) + node.getX();
			double yMax = height * Math.sin(2 * Math.PI * tMax) + node.getY();
			double xMin = width * Math.cos(2 * Math.PI * tMin) + node.getX();
			double yMin = height * Math.sin(2 * Math.PI * tMin) + node.getY();
			if((xMin - point.x) * (xMin - point.x) + (yMin - point.y) * (yMin - point.y)
				< (xMax - point.x) * (xMax - point.x) + (yMax - point.y) * (yMax - point.y)) {
				tMax = (tMin + tMax) / 2;
			}
			else if((xMin - point.x) * (xMin - point.x) + (yMin - point.y) * (yMin - point.y)
				> (xMax - point.x) * (xMax - point.x) + (yMax - point.y) * (yMax - point.y)) {
				tMin = (tMin + tMax) / 2;
			}
			else {
				tMin = (tMin + tMax) / 2;
			}
		}
		
		int x = (int)(width * Math.cos(2 * Math.PI * tMax) + node.getX());
		int y = (int)(height * Math.sin(2 * Math.PI * tMax) + node.getY());
		if((x - point.x) * (x - point.x) + (y - point.y) * (y - point.y) < 49) {
			return new NetworkNodeDescriptor(node, new Point(x, y), fm);
		}
		
		return new NetworkNodeDescriptor(node, point, fm);
	}
	
	private static boolean bounded(Point point, NetworkNode node, int width, int height) {
		//Bounds Check
		if(point.x < node.getX() - width - 5 || point.x > node.getX() + width + 5
				|| point.y < node.getY() - height - 5 || point.y > node.getY() + height + 5) {
			return false; 
		}
		return true;
	}
	
	private static double [] getQuadrant(Point point, NetworkNode node) {
		double [] result = new double[2];
		result[1] = .25;
		if(point.x < node.getX() && point.y > node.getY()) {
			result[0] = .25;
			result[1] = .5;
		}
		else if(point.x < node.getX() && point.y <= node.getY()) {
			result[0] = .5;
			result[1] = .75;
		}
		else if(point.x >= node.getX() && point.y <= node.getY()) {
			result[0] = .75;
			result[1] = 1;
		}
		return result;
	}
	
	@Override
	public void draw(Graphics2D g) {
		NetworkNode ob = (NetworkNode) object;
		int width = ((int)(nameWidth / 2 * 1.2) / 10 + 1) * 10;
		int height = ((int)(nameWidth / 2 * .5) / 10 + 1) * 10;
		Point upperLeft = new Point((int)(ob.getX() - width), (int)(ob.getY() - height));
		Point lowerLeft = new Point((int)(ob.getX() - width), (int)(ob.getY() + height));
		Point upperRight = new Point((int)(ob.getX() + width), (int)(ob.getY() - height));
		Point lowerRight = new Point((int)(ob.getX() + width), (int)(ob.getY() + height));
		
		g.setStroke(new BasicStroke(2));
		g.setColor(Paintbrush.seaFoam);
		g.drawLine(upperLeft.x, upperLeft.y, upperLeft.x + 5, upperLeft.y);
		g.drawLine(upperLeft.x, upperLeft.y, upperLeft.x, upperLeft.y + 5);
		
		g.drawLine(lowerLeft.x, lowerLeft.y, lowerLeft.x + 5, lowerLeft.y);
		g.drawLine(lowerLeft.x, lowerLeft.y, lowerLeft.x, lowerLeft.y - 5);
		
		g.drawLine(upperRight.x, upperRight.y, upperRight.x - 5, upperRight.y);
		g.drawLine(upperRight.x, upperRight.y, upperRight.x, upperRight.y + 5);
		
		g.drawLine(lowerRight.x, lowerRight.y, lowerRight.x - 5, lowerRight.y);
		g.drawLine(lowerRight.x, lowerRight.y, lowerRight.x, lowerRight.y - 5);
		g.setStroke(new BasicStroke(1));
	}

	public String toString() {
		return object.getName() + "\tindex: " + index;
	}

	public void setPressPoint(Point point) {
		pressPoint = point;
		dragPoint = point;
	}

	public void setDragPoint(Point point) {
		boolean moveNode = true;
		
		if(pressPoint != null) {
			int distance = (pressPoint.x - point.x) * (pressPoint.x - point.x)
						+ (pressPoint.y - point.y) * (pressPoint.y - point.y);
			moveNode = distance >= 9;
		}
		
		if(moveNode) {
			pressPoint = null;
			NetworkNode ob = (NetworkNode) object;
			ob.setLocation(ob.getX() - dragPoint.x + point.x, ob.getY() - dragPoint.y + point.y);
			dragPoint = point;
		}
	}
	
	public void setReleasePoint() {
		if(pressPoint == null) {
			NetworkNode ob = (NetworkNode) object;
			ob.finalizeLocation(ob.getX() - dragPoint.x + point.x, ob.getY() - dragPoint.y + point.y);
		}
		
		pressPoint = null;
		dragPoint = null;
	}
}
